1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.*;
10  import io.vavr.control.Option;
11  
12  import java.io.*;
13  import java.util.ArrayList;
14  import java.util.Comparator;
15  import java.util.NoSuchElementException;
16  import java.util.Objects;
17  import java.util.function.*;
18  import java.util.stream.Collector;
19  
20  /**
21   * An immutable {@code HashSet} implementation.
22   *
23   * @param <T> Component type
24   * @author Ruslan Sennov, Patryk Najda, Daniel Dietrich
25   */
26  public final class LinkedHashSet<T> implements Set<T>, Serializable {
27  
28      private static final long serialVersionUID = 1L;
29  
30      private static final LinkedHashSet<?> EMPTY = new LinkedHashSet<>(LinkedHashMap.empty());
31  
32      private final LinkedHashMap<T, Object> map;
33  
34      private LinkedHashSet(LinkedHashMap<T, Object> map) {
35          this.map = map;
36      }
37  
38      @SuppressWarnings("unchecked")
39      public static <T> LinkedHashSet<T> empty() {
40          return (LinkedHashSet<T>) EMPTY;
41      }
42  
43      static <T> LinkedHashSet<T> wrap(LinkedHashMap<T, Object> map) {
44          return new LinkedHashSet<>(map);
45      }
46  
47      /**
48       * Returns a {@link Collector} which may be used in conjunction with
49       * {@link java.util.stream.Stream#collect(Collector)} to obtain a {@link LinkedHashSet}.
50       *
51       * @param <T> Component type of the LinkedHashSet.
52       * @return A io.vavr.collection.LinkedHashSet Collector.
53       */
54      public static <T> Collector<T, ArrayList<T>, LinkedHashSet<T>> collector() {
55          final Supplier<ArrayList<T>> supplier = ArrayList::new;
56          final BiConsumer<ArrayList<T>, T> accumulator = ArrayList::add;
57          final BinaryOperator<ArrayList<T>> combiner = (left, right) -> {
58              left.addAll(right);
59              return left;
60          };
61          final Function<ArrayList<T>, LinkedHashSet<T>> finisher = LinkedHashSet::ofAll;
62          return Collector.of(supplier, accumulator, combiner, finisher);
63      }
64  
65      /**
66       * Narrows a widened {@code LinkedHashSet<? extends T>} to {@code LinkedHashSet<T>}
67       * by performing a type-safe cast. This is eligible because immutable/read-only
68       * collections are covariant.
69       *
70       * @param linkedHashSet A {@code LinkedHashSet}.
71       * @param <T>           Component type of the {@code linkedHashSet}.
72       * @return the given {@code linkedHashSet} instance as narrowed type {@code LinkedHashSet<T>}.
73       */
74      @SuppressWarnings("unchecked")
75      public static <T> LinkedHashSet<T> narrow(LinkedHashSet<? extends T> linkedHashSet) {
76          return (LinkedHashSet<T>) linkedHashSet;
77      }
78  
79      /**
80       * Returns a singleton {@code LinkedHashSet}, i.e. a {@code LinkedHashSet} of one element.
81       *
82       * @param element An element.
83       * @param <T>     The component type
84       * @return A new LinkedHashSet instance containing the given element
85       */
86      public static <T> LinkedHashSet<T> of(T element) {
87          return LinkedHashSet.<T> empty().add(element);
88      }
89  
90      /**
91       * Creates a LinkedHashSet of the given elements.
92       *
93       * <pre><code>LinkedHashSet.of(1, 2, 3, 4)</code></pre>
94       *
95       * @param <T>      Component type of the LinkedHashSet.
96       * @param elements Zero or more elements.
97       * @return A set containing the given elements.
98       * @throws NullPointerException if {@code elements} is null
99       */
100     @SafeVarargs
101     public static <T> LinkedHashSet<T> of(T... elements) {
102         Objects.requireNonNull(elements, "elements is null");
103         LinkedHashMap<T, Object> map = LinkedHashMap.empty();
104         for (T element : elements) {
105             map = map.put(element, element);
106         }
107         return map.isEmpty() ? LinkedHashSet.empty() : new LinkedHashSet<>(map);
108     }
109 
110     /**
111      * Returns a LinkedHashSet containing {@code n} values of a given Function {@code f}
112      * over a range of integer values from 0 to {@code n - 1}.
113      *
114      * @param <T> Component type of the LinkedHashSet
115      * @param n   The number of elements in the LinkedHashSet
116      * @param f   The Function computing element values
117      * @return A LinkedHashSet consisting of elements {@code f(0),f(1), ..., f(n - 1)}
118      * @throws NullPointerException if {@code f} is null
119      */
120     public static <T> LinkedHashSet<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
121         Objects.requireNonNull(f, "f is null");
122         return Collections.tabulate(n, f, LinkedHashSet.empty(), LinkedHashSet::of);
123     }
124 
125     /**
126      * Returns a LinkedHashSet containing {@code n} values supplied by a given Supplier {@code s}.
127      *
128      * @param <T> Component type of the LinkedHashSet
129      * @param n   The number of elements in the LinkedHashSet
130      * @param s   The Supplier computing element values
131      * @return A LinkedHashSet of size {@code n}, where each element contains the result supplied by {@code s}.
132      * @throws NullPointerException if {@code s} is null
133      */
134     public static <T> LinkedHashSet<T> fill(int n, Supplier<? extends T> s) {
135         Objects.requireNonNull(s, "s is null");
136         return Collections.fill(n, s, LinkedHashSet.empty(), LinkedHashSet::of);
137     }
138 
139     /**
140      * Creates a LinkedHashSet of the given elements.
141      *
142      * @param elements Set elements
143      * @param <T>      The value type
144      * @return A new LinkedHashSet containing the given entries
145      */
146     @SuppressWarnings("unchecked")
147     public static <T> LinkedHashSet<T> ofAll(Iterable<? extends T> elements) {
148         Objects.requireNonNull(elements, "elements is null");
149         if (elements instanceof LinkedHashSet) {
150             return (LinkedHashSet<T>) elements;
151         } else {
152             final LinkedHashMap<T, Object> mao = addAll(LinkedHashMap.empty(), elements);
153             return mao.isEmpty() ? empty() : new LinkedHashSet<>(mao);
154         }
155     }
156 
157     /**
158      * Creates a LinkedHashSet that contains the elements of the given {@link java.util.stream.Stream}.
159      *
160      * @param javaStream A {@link java.util.stream.Stream}
161      * @param <T>        Component type of the Stream.
162      * @return A LinkedHashSet containing the given elements in the same order.
163      */
164     public static <T> LinkedHashSet<T> ofAll(java.util.stream.Stream<? extends T> javaStream) {
165         Objects.requireNonNull(javaStream, "javaStream is null");
166         return ofAll(Iterator.ofAll(javaStream.iterator()));
167     }
168 
169     /**
170      * Creates a LinkedHashSet from boolean values.
171      *
172      * @param elements boolean values
173      * @return A new LinkedHashSet of Boolean values
174      * @throws NullPointerException if elements is null
175      */
176     public static LinkedHashSet<Boolean> ofAll(boolean... elements) {
177         Objects.requireNonNull(elements, "elements is null");
178         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
179     }
180 
181     /**
182      * Creates a LinkedHashSet from byte values.
183      *
184      * @param elements byte values
185      * @return A new LinkedHashSet of Byte values
186      * @throws NullPointerException if elements is null
187      */
188     public static LinkedHashSet<Byte> ofAll(byte... elements) {
189         Objects.requireNonNull(elements, "elements is null");
190         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
191     }
192 
193     /**
194      * Creates a LinkedHashSet from char values.
195      *
196      * @param elements char values
197      * @return A new LinkedHashSet of Character values
198      * @throws NullPointerException if elements is null
199      */
200     public static LinkedHashSet<Character> ofAll(char... elements) {
201         Objects.requireNonNull(elements, "elements is null");
202         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
203     }
204 
205     /**
206      * Creates a LinkedHashSet from double values.
207      *
208      * @param elements double values
209      * @return A new LinkedHashSet of Double values
210      * @throws NullPointerException if elements is null
211      */
212     public static LinkedHashSet<Double> ofAll(double... elements) {
213         Objects.requireNonNull(elements, "elements is null");
214         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
215     }
216 
217     /**
218      * Creates a LinkedHashSet from float values.
219      *
220      * @param elements a float values
221      * @return A new LinkedHashSet of Float values
222      * @throws NullPointerException if elements is null
223      */
224     public static LinkedHashSet<Float> ofAll(float... elements) {
225         Objects.requireNonNull(elements, "elements is null");
226         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
227     }
228 
229     /**
230      * Creates a LinkedHashSet from int values.
231      *
232      * @param elements int values
233      * @return A new LinkedHashSet of Integer values
234      * @throws NullPointerException if elements is null
235      */
236     public static LinkedHashSet<Integer> ofAll(int... elements) {
237         Objects.requireNonNull(elements, "elements is null");
238         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
239     }
240 
241     /**
242      * Creates a LinkedHashSet from long values.
243      *
244      * @param elements long values
245      * @return A new LinkedHashSet of Long values
246      * @throws NullPointerException if elements is null
247      */
248     public static LinkedHashSet<Long> ofAll(long... elements) {
249         Objects.requireNonNull(elements, "elements is null");
250         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
251     }
252 
253     /**
254      * Creates a LinkedHashSet from short values.
255      *
256      * @param elements short values
257      * @return A new LinkedHashSet of Short values
258      * @throws NullPointerException if elements is null
259      */
260     public static LinkedHashSet<Short> ofAll(short... elements) {
261         Objects.requireNonNull(elements, "elements is null");
262         return LinkedHashSet.ofAll(Iterator.ofAll(elements));
263     }
264 
265     /**
266      * Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
267      * <p>
268      * Examples:
269      * <pre>
270      * <code>
271      * LinkedHashSet.range(0, 0)  // = LinkedHashSet()
272      * LinkedHashSet.range(2, 0)  // = LinkedHashSet()
273      * LinkedHashSet.range(-2, 2) // = LinkedHashSet(-2, -1, 0, 1)
274      * </code>
275      * </pre>
276      *
277      * @param from        the first number
278      * @param toExclusive the last number + 1
279      * @return a range of int values as specified or the empty range if {@code from >= toExclusive}
280      */
281     public static LinkedHashSet<Integer> range(int from, int toExclusive) {
282         return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
283     }
284 
285     public static LinkedHashSet<Character> range(char from, char toExclusive) {
286         return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
287     }
288 
289     /**
290      * Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
291      * with {@code step}.
292      * <p>
293      * Examples:
294      * <pre>
295      * <code>
296      * LinkedHashSet.rangeBy(1, 3, 1)  // = LinkedHashSet(1, 2)
297      * LinkedHashSet.rangeBy(1, 4, 2)  // = LinkedHashSet(1, 3)
298      * LinkedHashSet.rangeBy(4, 1, -2) // = LinkedHashSet(4, 2)
299      * LinkedHashSet.rangeBy(4, 1, 2)  // = LinkedHashSet()
300      * </code>
301      * </pre>
302      *
303      * @param from        the first number
304      * @param toExclusive the last number + 1
305      * @param step        the step
306      * @return a range of long values as specified or the empty range if<br>
307      * {@code from >= toInclusive} and {@code step > 0} or<br>
308      * {@code from <= toInclusive} and {@code step < 0}
309      * @throws IllegalArgumentException if {@code step} is zero
310      */
311     public static LinkedHashSet<Integer> rangeBy(int from, int toExclusive, int step) {
312         return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
313     }
314 
315     public static LinkedHashSet<Character> rangeBy(char from, char toExclusive, int step) {
316         return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
317     }
318 
319     @GwtIncompatible
320     public static LinkedHashSet<Double> rangeBy(double from, double toExclusive, double step) {
321         return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
322     }
323 
324     /**
325      * Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
326      * <p>
327      * Examples:
328      * <pre>
329      * <code>
330      * LinkedHashSet.range(0L, 0L)  // = LinkedHashSet()
331      * LinkedHashSet.range(2L, 0L)  // = LinkedHashSet()
332      * LinkedHashSet.range(-2L, 2L) // = LinkedHashSet(-2L, -1L, 0L, 1L)
333      * </code>
334      * </pre>
335      *
336      * @param from        the first number
337      * @param toExclusive the last number + 1
338      * @return a range of long values as specified or the empty range if {@code from >= toExclusive}
339      */
340     public static LinkedHashSet<Long> range(long from, long toExclusive) {
341         return LinkedHashSet.ofAll(Iterator.range(from, toExclusive));
342     }
343 
344     /**
345      * Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
346      * with {@code step}.
347      * <p>
348      * Examples:
349      * <pre>
350      * <code>
351      * LinkedHashSet.rangeBy(1L, 3L, 1L)  // = LinkedHashSet(1L, 2L)
352      * LinkedHashSet.rangeBy(1L, 4L, 2L)  // = LinkedHashSet(1L, 3L)
353      * LinkedHashSet.rangeBy(4L, 1L, -2L) // = LinkedHashSet(4L, 2L)
354      * LinkedHashSet.rangeBy(4L, 1L, 2L)  // = LinkedHashSet()
355      * </code>
356      * </pre>
357      *
358      * @param from        the first number
359      * @param toExclusive the last number + 1
360      * @param step        the step
361      * @return a range of long values as specified or the empty range if<br>
362      * {@code from >= toInclusive} and {@code step > 0} or<br>
363      * {@code from <= toInclusive} and {@code step < 0}
364      * @throws IllegalArgumentException if {@code step} is zero
365      */
366     public static LinkedHashSet<Long> rangeBy(long from, long toExclusive, long step) {
367         return LinkedHashSet.ofAll(Iterator.rangeBy(from, toExclusive, step));
368     }
369 
370     /**
371      * Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toInclusive}.
372      * <p>
373      * Examples:
374      * <pre>
375      * <code>
376      * LinkedHashSet.rangeClosed(0, 0)  // = LinkedHashSet(0)
377      * LinkedHashSet.rangeClosed(2, 0)  // = LinkedHashSet()
378      * LinkedHashSet.rangeClosed(-2, 2) // = LinkedHashSet(-2, -1, 0, 1, 2)
379      * </code>
380      * </pre>
381      *
382      * @param from        the first number
383      * @param toInclusive the last number
384      * @return a range of int values as specified or the empty range if {@code from > toInclusive}
385      */
386     public static LinkedHashSet<Integer> rangeClosed(int from, int toInclusive) {
387         return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
388     }
389 
390     public static LinkedHashSet<Character> rangeClosed(char from, char toInclusive) {
391         return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
392     }
393 
394     /**
395      * Creates a LinkedHashSet of int numbers starting from {@code from}, extending to {@code toInclusive},
396      * with {@code step}.
397      * <p>
398      * Examples:
399      * <pre>
400      * <code>
401      * LinkedHashSet.rangeClosedBy(1, 3, 1)  // = LinkedHashSet(1, 2, 3)
402      * LinkedHashSet.rangeClosedBy(1, 4, 2)  // = LinkedHashSet(1, 3)
403      * LinkedHashSet.rangeClosedBy(4, 1, -2) // = LinkedHashSet(4, 2)
404      * LinkedHashSet.rangeClosedBy(4, 1, 2)  // = LinkedHashSet()
405      * </code>
406      * </pre>
407      *
408      * @param from        the first number
409      * @param toInclusive the last number
410      * @param step        the step
411      * @return a range of int values as specified or the empty range if<br>
412      * {@code from > toInclusive} and {@code step > 0} or<br>
413      * {@code from < toInclusive} and {@code step < 0}
414      * @throws IllegalArgumentException if {@code step} is zero
415      */
416     public static LinkedHashSet<Integer> rangeClosedBy(int from, int toInclusive, int step) {
417         return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
418     }
419 
420     public static LinkedHashSet<Character> rangeClosedBy(char from, char toInclusive, int step) {
421         return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
422     }
423 
424     @GwtIncompatible
425     public static LinkedHashSet<Double> rangeClosedBy(double from, double toInclusive, double step) {
426         return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
427     }
428 
429     /**
430      * Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toInclusive}.
431      * <p>
432      * Examples:
433      * <pre>
434      * <code>
435      * LinkedHashSet.rangeClosed(0L, 0L)  // = LinkedHashSet(0L)
436      * LinkedHashSet.rangeClosed(2L, 0L)  // = LinkedHashSet()
437      * LinkedHashSet.rangeClosed(-2L, 2L) // = LinkedHashSet(-2L, -1L, 0L, 1L, 2L)
438      * </code>
439      * </pre>
440      *
441      * @param from        the first number
442      * @param toInclusive the last number
443      * @return a range of long values as specified or the empty range if {@code from > toInclusive}
444      */
445     public static LinkedHashSet<Long> rangeClosed(long from, long toInclusive) {
446         return LinkedHashSet.ofAll(Iterator.rangeClosed(from, toInclusive));
447     }
448 
449     /**
450      * Creates a LinkedHashSet of long numbers starting from {@code from}, extending to {@code toInclusive},
451      * with {@code step}.
452      * <p>
453      * Examples:
454      * <pre>
455      * <code>
456      * LinkedHashSet.rangeClosedBy(1L, 3L, 1L)  // = LinkedHashSet(1L, 2L, 3L)
457      * LinkedHashSet.rangeClosedBy(1L, 4L, 2L)  // = LinkedHashSet(1L, 3L)
458      * LinkedHashSet.rangeClosedBy(4L, 1L, -2L) // = LinkedHashSet(4L, 2L)
459      * LinkedHashSet.rangeClosedBy(4L, 1L, 2L)  // = LinkedHashSet()
460      * </code>
461      * </pre>
462      *
463      * @param from        the first number
464      * @param toInclusive the last number
465      * @param step        the step
466      * @return a range of int values as specified or the empty range if<br>
467      * {@code from > toInclusive} and {@code step > 0} or<br>
468      * {@code from < toInclusive} and {@code step < 0}
469      * @throws IllegalArgumentException if {@code step} is zero
470      */
471     public static LinkedHashSet<Long> rangeClosedBy(long from, long toInclusive, long step) {
472         return LinkedHashSet.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
473     }
474 
475     @Override
476     public LinkedHashSet<T> add(T element) {
477         return contains(element) ? this : new LinkedHashSet<>(map.put(element, element));
478     }
479 
480     @Override
481     public LinkedHashSet<T> addAll(Iterable<? extends T> elements) {
482         Objects.requireNonNull(elements, "elements is null");
483         if (isEmpty() && elements instanceof LinkedHashSet) {
484             @SuppressWarnings("unchecked")
485             final LinkedHashSet<T> set = (LinkedHashSet<T>) elements;
486             return set;
487         }
488         final LinkedHashMap<T, Object> that = addAll(map, elements);
489         if (that.size() == map.size()) {
490             return this;
491         } else {
492             return new LinkedHashSet<>(that);
493         }
494     }
495 
496     @Override
497     public <R> LinkedHashSet<R> collect(PartialFunction<? super T, ? extends R> partialFunction) {
498         return ofAll(iterator().<R> collect(partialFunction));
499     }
500 
501     @Override
502     public boolean contains(T element) {
503         return map.get(element).isDefined();
504     }
505 
506     @Override
507     public LinkedHashSet<T> diff(Set<? extends T> elements) {
508         Objects.requireNonNull(elements, "elements is null");
509         if (isEmpty() || elements.isEmpty()) {
510             return this;
511         } else {
512             return removeAll(elements);
513         }
514     }
515 
516     @Override
517     public LinkedHashSet<T> distinct() {
518         return this;
519     }
520 
521     @Override
522     public LinkedHashSet<T> distinctBy(Comparator<? super T> comparator) {
523         Objects.requireNonNull(comparator, "comparator is null");
524         return LinkedHashSet.ofAll(iterator().distinctBy(comparator));
525     }
526 
527     @Override
528     public <U> LinkedHashSet<T> distinctBy(Function<? super T, ? extends U> keyExtractor) {
529         Objects.requireNonNull(keyExtractor, "keyExtractor is null");
530         return LinkedHashSet.ofAll(iterator().distinctBy(keyExtractor));
531     }
532 
533     @Override
534     public LinkedHashSet<T> drop(int n) {
535         if (n <= 0) {
536             return this;
537         } else {
538             return LinkedHashSet.ofAll(iterator().drop(n));
539         }
540     }
541 
542     @Override
543     public LinkedHashSet<T> dropRight(int n) {
544         if (n <= 0) {
545             return this;
546         } else {
547             return LinkedHashSet.ofAll(iterator().dropRight(n));
548         }
549     }
550 
551     @Override
552     public LinkedHashSet<T> dropUntil(Predicate<? super T> predicate) {
553         Objects.requireNonNull(predicate, "predicate is null");
554         return dropWhile(predicate.negate());
555     }
556 
557     @Override
558     public LinkedHashSet<T> dropWhile(Predicate<? super T> predicate) {
559         Objects.requireNonNull(predicate, "predicate is null");
560         final LinkedHashSet<T> dropped = LinkedHashSet.ofAll(iterator().dropWhile(predicate));
561         return dropped.length() == length() ? this : dropped;
562     }
563 
564     @Override
565     public LinkedHashSet<T> filter(Predicate<? super T> predicate) {
566         Objects.requireNonNull(predicate, "predicate is null");
567         final LinkedHashSet<T> filtered = LinkedHashSet.ofAll(iterator().filter(predicate));
568         return filtered.length() == length() ? this : filtered;
569     }
570 
571     @Override
572     public <U> LinkedHashSet<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper) {
573         Objects.requireNonNull(mapper, "mapper is null");
574         if (isEmpty()) {
575             return empty();
576         } else {
577             final LinkedHashMap<U, Object> that = foldLeft(LinkedHashMap.empty(),
578                     (tree, t) -> addAll(tree, mapper.apply(t)));
579             return new LinkedHashSet<>(that);
580         }
581     }
582 
583     @Override
584     public <U> U foldRight(U zero, BiFunction<? super T, ? super U, ? extends U> f) {
585         Objects.requireNonNull(f, "f is null");
586         return iterator().foldRight(zero, f);
587     }
588 
589     @Override
590     public <C> Map<C, LinkedHashSet<T>> groupBy(Function<? super T, ? extends C> classifier) {
591         return Collections.groupBy(this, classifier, LinkedHashSet::ofAll);
592     }
593 
594     @Override
595     public Iterator<LinkedHashSet<T>> grouped(int size) {
596         return sliding(size, size);
597     }
598 
599     @Override
600     public boolean hasDefiniteSize() {
601         return true;
602     }
603 
604     @Override
605     public T head() {
606         if (map.isEmpty()) {
607             throw new NoSuchElementException("head of empty set");
608         }
609         return iterator().next();
610     }
611 
612     @Override
613     public Option<T> headOption() {
614         return iterator().headOption();
615     }
616 
617     @Override
618     public LinkedHashSet<T> init() {
619         if (map.isEmpty()) {
620             throw new UnsupportedOperationException("tail of empty set");
621         } else {
622             return new LinkedHashSet<>(map.init());
623         }
624     }
625 
626     @Override
627     public Option<LinkedHashSet<T>> initOption() {
628         return isEmpty() ? Option.none() : Option.some(init());
629     }
630 
631     @Override
632     public LinkedHashSet<T> intersect(Set<? extends T> elements) {
633         Objects.requireNonNull(elements, "elements is null");
634         if (isEmpty() || elements.isEmpty()) {
635             return empty();
636         } else {
637             return retainAll(elements);
638         }
639     }
640 
641     /**
642      * An {@code LinkedHashSet}'s value is computed synchronously.
643      *
644      * @return false
645      */
646     @Override
647     public boolean isAsync() {
648         return false;
649     }
650 
651     @Override
652     public boolean isEmpty() {
653         return map.isEmpty();
654     }
655 
656     /**
657      * An {@code LinkedHashSet}'s value is computed eagerly.
658      *
659      * @return false
660      */
661     @Override
662     public boolean isLazy() {
663         return false;
664     }
665 
666     @Override
667     public boolean isTraversableAgain() {
668         return true;
669     }
670 
671     @Override
672     public boolean isSequential() {
673         return true;
674     }
675 
676     @Override
677     public Iterator<T> iterator() {
678         return map.iterator().map(t -> t._1);
679     }
680 
681     @Override
682     public int length() {
683         return map.size();
684     }
685 
686     @Override
687     public <U> LinkedHashSet<U> map(Function<? super T, ? extends U> mapper) {
688         Objects.requireNonNull(mapper, "mapper is null");
689         if (isEmpty()) {
690             return empty();
691         } else {
692             final LinkedHashMap<U, Object> that = foldLeft(LinkedHashMap.empty(), (tree, t) -> {
693                 final U u = mapper.apply(t);
694                 return tree.put(u, u);
695             });
696             return new LinkedHashSet<>(that);
697         }
698     }
699 
700     @Override
701     public String mkString(CharSequence prefix, CharSequence delimiter, CharSequence suffix) {
702         return iterator().mkString(prefix, delimiter, suffix);
703     }
704 
705     @Override
706     public LinkedHashSet<T> orElse(Iterable<? extends T> other) {
707         return isEmpty() ? ofAll(other) : this;
708     }
709 
710     @Override
711     public LinkedHashSet<T> orElse(Supplier<? extends Iterable<? extends T>> supplier) {
712         return isEmpty() ? ofAll(supplier.get()) : this;
713     }
714 
715     @Override
716     public Tuple2<LinkedHashSet<T>, LinkedHashSet<T>> partition(Predicate<? super T> predicate) {
717         Objects.requireNonNull(predicate, "predicate is null");
718         final Tuple2<Iterator<T>, Iterator<T>> p = iterator().partition(predicate);
719         return Tuple.of(LinkedHashSet.ofAll(p._1), LinkedHashSet.ofAll(p._2));
720     }
721 
722     @Override
723     public LinkedHashSet<T> peek(Consumer<? super T> action) {
724         Objects.requireNonNull(action, "action is null");
725         if (!isEmpty()) {
726             action.accept(iterator().head());
727         }
728         return this;
729     }
730 
731     @Override
732     public LinkedHashSet<T> remove(T element) {
733         final LinkedHashMap<T, Object> newMap = map.remove(element);
734         return (newMap == map) ? this : new LinkedHashSet<>(newMap);
735     }
736 
737     @Override
738     public LinkedHashSet<T> removeAll(Iterable<? extends T> elements) {
739         return Collections.removeAll(this, elements);
740     }
741 
742     @Override
743     public LinkedHashSet<T> replace(T currentElement, T newElement) {
744         if (!Objects.equals(currentElement, newElement) && contains(currentElement)) {
745             final Tuple2<T, Object> currentPair = Tuple.of(currentElement, currentElement);
746             final Tuple2<T, Object> newPair = Tuple.of(newElement, newElement);
747             final LinkedHashMap<T, Object> newMap = map.replace(currentPair, newPair);
748             return new LinkedHashSet<>(newMap);
749         } else {
750             return this;
751         }
752     }
753 
754     @Override
755     public LinkedHashSet<T> replaceAll(T currentElement, T newElement) {
756         return replace(currentElement, newElement);
757     }
758 
759     @Override
760     public LinkedHashSet<T> retainAll(Iterable<? extends T> elements) {
761         return Collections.retainAll(this, elements);
762     }
763 
764     @Override
765     public LinkedHashSet<T> scan(T zero, BiFunction<? super T, ? super T, ? extends T> operation) {
766         return scanLeft(zero, operation);
767     }
768 
769     @Override
770     public <U> LinkedHashSet<U> scanLeft(U zero, BiFunction<? super U, ? super T, ? extends U> operation) {
771         return Collections.scanLeft(this, zero, operation, LinkedHashSet::ofAll);
772     }
773 
774     @Override
775     public <U> LinkedHashSet<U> scanRight(U zero, BiFunction<? super T, ? super U, ? extends U> operation) {
776         return Collections.scanRight(this, zero, operation, LinkedHashSet::ofAll);
777     }
778 
779     @Override
780     public Iterator<LinkedHashSet<T>> slideBy(Function<? super T, ?> classifier) {
781         return iterator().slideBy(classifier).map(LinkedHashSet::ofAll);
782     }
783 
784     @Override
785     public Iterator<LinkedHashSet<T>> sliding(int size) {
786         return sliding(size, 1);
787     }
788 
789     @Override
790     public Iterator<LinkedHashSet<T>> sliding(int size, int step) {
791         return iterator().sliding(size, step).map(LinkedHashSet::ofAll);
792     }
793 
794     @Override
795     public Tuple2<LinkedHashSet<T>, LinkedHashSet<T>> span(Predicate<? super T> predicate) {
796         Objects.requireNonNull(predicate, "predicate is null");
797         final Tuple2<Iterator<T>, Iterator<T>> t = iterator().span(predicate);
798         return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2));
799     }
800 
801     @Override
802     public LinkedHashSet<T> tail() {
803         if (map.isEmpty()) {
804             throw new UnsupportedOperationException("tail of empty set");
805         }
806         return remove(head());
807     }
808 
809     @Override
810     public Option<LinkedHashSet<T>> tailOption() {
811         return isEmpty() ? Option.none() : Option.some(tail());
812     }
813 
814     @Override
815     public LinkedHashSet<T> take(int n) {
816         if (map.size() <= n) {
817             return this;
818         }
819         return LinkedHashSet.ofAll(() -> iterator().take(n));
820     }
821 
822     @Override
823     public LinkedHashSet<T> takeRight(int n) {
824         if (map.size() <= n) {
825             return this;
826         }
827         return LinkedHashSet.ofAll(() -> iterator().takeRight(n));
828     }
829 
830     @Override
831     public LinkedHashSet<T> takeUntil(Predicate<? super T> predicate) {
832         Objects.requireNonNull(predicate, "predicate is null");
833         return takeWhile(predicate.negate());
834     }
835 
836     @Override
837     public LinkedHashSet<T> takeWhile(Predicate<? super T> predicate) {
838         Objects.requireNonNull(predicate, "predicate is null");
839         final LinkedHashSet<T> taken = LinkedHashSet.ofAll(iterator().takeWhile(predicate));
840         return taken.length() == length() ? this : taken;
841     }
842 
843     /**
844      * Transforms this {@code LinkedHashSet}.
845      *
846      * @param f   A transformation
847      * @param <U> Type of transformation result
848      * @return An instance of type {@code U}
849      * @throws NullPointerException if {@code f} is null
850      */
851     public <U> U transform(Function<? super LinkedHashSet<T>, ? extends U> f) {
852         Objects.requireNonNull(f, "f is null");
853         return f.apply(this);
854     }
855 
856     @Override
857     public java.util.LinkedHashSet<T> toJavaSet() {
858         return toJavaSet(java.util.LinkedHashSet::new);
859     }
860 
861     @SuppressWarnings("unchecked")
862     @Override
863     public LinkedHashSet<T> union(Set<? extends T> elements) {
864         Objects.requireNonNull(elements, "elements is null");
865         if (isEmpty()) {
866             if (elements instanceof LinkedHashSet) {
867                 return (LinkedHashSet<T>) elements;
868             } else {
869                 return LinkedHashSet.ofAll(elements);
870             }
871         } else if (elements.isEmpty()) {
872             return this;
873         } else {
874             final LinkedHashMap<T, Object> that = addAll(map, elements);
875             if (that.size() == map.size()) {
876                 return this;
877             } else {
878                 return new LinkedHashSet<>(that);
879             }
880         }
881     }
882 
883     @Override
884     public <T1, T2> Tuple2<LinkedHashSet<T1>, LinkedHashSet<T2>> unzip(
885             Function<? super T, Tuple2<? extends T1, ? extends T2>> unzipper) {
886         Objects.requireNonNull(unzipper, "unzipper is null");
887         final Tuple2<Iterator<T1>, Iterator<T2>> t = iterator().unzip(unzipper);
888         return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2));
889     }
890 
891     @Override
892     public <T1, T2, T3> Tuple3<LinkedHashSet<T1>, LinkedHashSet<T2>, LinkedHashSet<T3>> unzip3(
893             Function<? super T, Tuple3<? extends T1, ? extends T2, ? extends T3>> unzipper) {
894         Objects.requireNonNull(unzipper, "unzipper is null");
895         final Tuple3<Iterator<T1>, Iterator<T2>, Iterator<T3>> t = iterator().unzip3(unzipper);
896         return Tuple.of(LinkedHashSet.ofAll(t._1), LinkedHashSet.ofAll(t._2), LinkedHashSet.ofAll(t._3));
897     }
898 
899     @Override
900     public <U> LinkedHashSet<Tuple2<T, U>> zip(Iterable<? extends U> that) {
901         return zipWith(that, Tuple::of);
902     }
903 
904     @Override
905     public <U, R> LinkedHashSet<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper) {
906         Objects.requireNonNull(that, "that is null");
907         Objects.requireNonNull(mapper, "mapper is null");
908         return LinkedHashSet.ofAll(iterator().zipWith(that, mapper));
909     }
910 
911     @Override
912     public <U> LinkedHashSet<Tuple2<T, U>> zipAll(Iterable<? extends U> that, T thisElem, U thatElem) {
913         Objects.requireNonNull(that, "that is null");
914         return LinkedHashSet.ofAll(iterator().zipAll(that, thisElem, thatElem));
915     }
916 
917     @Override
918     public LinkedHashSet<Tuple2<T, Integer>> zipWithIndex() {
919         return zipWithIndex(Tuple::of);
920     }
921 
922     @Override
923     public <U> LinkedHashSet<U> zipWithIndex(BiFunction<? super T, ? super Integer, ? extends U> mapper) {
924         Objects.requireNonNull(mapper, "mapper is null");
925         return LinkedHashSet.ofAll(iterator().zipWithIndex(mapper));
926     }
927 
928     // -- Object
929 
930     @Override
931     public boolean equals(Object o) {
932         return Collections.equals(this, o);
933     }
934 
935     @Override
936     public int hashCode() {
937         return Collections.hashUnordered(this);
938     }
939 
940     @Override
941     public String stringPrefix() {
942         return "LinkedHashSet";
943     }
944 
945     @Override
946     public String toString() {
947         return mkString(stringPrefix() + "(", ", ", ")");
948     }
949 
950     private static <T> LinkedHashMap<T, Object> addAll(LinkedHashMap<T, Object> initial,
951             Iterable<? extends T> additional) {
952         LinkedHashMap<T, Object> that = initial;
953         for (T t : additional) {
954             that = that.put(t, t);
955         }
956         return that;
957     }
958 
959     // -- Serialization
960 
961     /**
962      * {@code writeReplace} method for the serialization proxy pattern.
963      * <p>
964      * The presence of this method causes the serialization system to emit a SerializationProxy instance instead of
965      * an instance of the enclosing class.
966      *
967      * @return A SerializationProxy for this enclosing class.
968      */
969     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
970     private Object writeReplace() {
971         return new SerializationProxy<>(this.map);
972     }
973 
974     /**
975      * {@code readObject} method for the serialization proxy pattern.
976      * <p>
977      * Guarantees that the serialization system will never generate a serialized instance of the enclosing class.
978      *
979      * @param stream An object serialization stream.
980      * @throws InvalidObjectException This method will throw with the message "Proxy required".
981      */
982     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
983     private void readObject(ObjectInputStream stream) throws InvalidObjectException {
984         throw new InvalidObjectException("Proxy required");
985     }
986 
987     /**
988      * A serialization proxy which, in this context, is used to deserialize immutable, linked Lists with final
989      * instance fields.
990      *
991      * @param <T> The component type of the underlying list.
992      */
993     // DEV NOTE: The serialization proxy pattern is not compatible with non-final, i.e. extendable,
994     // classes. Also, it may not be compatible with circular object graphs.
995     @GwtIncompatible("The Java serialization protocol is explicitly not supported")
996     private static final class SerializationProxy<T> implements Serializable {
997 
998         private static final long serialVersionUID = 1L;
999 
1000         // the instance to be serialized/deserialized
1001         private transient LinkedHashMap<T, Object> map;
1002 
1003         /**
1004          * Constructor for the case of serialization, called by {@link LinkedHashSet#writeReplace()}.
1005          * <p/>
1006          * The constructor of a SerializationProxy takes an argument that concisely represents the logical state of
1007          * an instance of the enclosing class.
1008          *
1009          * @param map a Cons
1010          */
1011         SerializationProxy(LinkedHashMap<T, Object> map) {
1012             this.map = map;
1013         }
1014 
1015         /**
1016          * Write an object to a serialization stream.
1017          *
1018          * @param s An object serialization stream.
1019          * @throws IOException If an error occurs writing to the stream.
1020          */
1021         private void writeObject(ObjectOutputStream s) throws IOException {
1022             s.defaultWriteObject();
1023             s.writeInt(map.size());
1024             for (Tuple2<T, Object> e : map) {
1025                 s.writeObject(e._1);
1026             }
1027         }
1028 
1029         /**
1030          * Read an object from a deserialization stream.
1031          *
1032          * @param s An object deserialization stream.
1033          * @throws ClassNotFoundException If the object's class read from the stream cannot be found.
1034          * @throws InvalidObjectException If the stream contains no list elements.
1035          * @throws IOException            If an error occurs reading from the stream.
1036          */
1037         private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
1038             s.defaultReadObject();
1039             final int size = s.readInt();
1040             if (size < 0) {
1041                 throw new InvalidObjectException("No elements");
1042             }
1043             LinkedHashMap<T, Object> temp = LinkedHashMap.empty();
1044             for (int i = 0; i < size; i++) {
1045                 @SuppressWarnings("unchecked")
1046                 final T element = (T) s.readObject();
1047                 temp = temp.put(element, element);
1048             }
1049             map = temp;
1050         }
1051 
1052         /**
1053          * {@code readResolve} method for the serialization proxy pattern.
1054          * <p>
1055          * Returns a logically equivalent instance of the enclosing class. The presence of this method causes the
1056          * serialization system to translate the serialization proxy back into an instance of the enclosing class
1057          * upon deserialization.
1058          *
1059          * @return A deserialized instance of the enclosing class.
1060          */
1061         private Object readResolve() {
1062             return map.isEmpty() ? LinkedHashSet.empty() : new LinkedHashSet<>(map);
1063         }
1064     }
1065 }